package com.zlm.design.combined.clac;

import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zlm
 * @date 2025/4/21
 */
public class ExpressionParser {
    //中缀表达式
    final String infixExpression;
    //指针
    int point = 0;

    Map<String, Integer> variables;

    public ExpressionParser(String infixExpression, Map<String, Integer> variables) {
        this.infixExpression = infixExpression;
        this.variables = variables;
    }

    public ExpressionParser(String infixExpression) {
        this.infixExpression = infixExpression;
    }

    /**
     * 中缀表达式转后缀表达式
     *
     * @return
     */
    public List<String> toSuffix() {
        List<String> suffix = new ArrayList<>();
        LinkedList<String> stack = new LinkedList<>();

        while (point < infixExpression.length()) {
            char c = infixExpression.charAt(point);
            // 跳过空格
            if (Character.isWhitespace(c)) {
                point++;
                continue;
            } else if (c == '(') {
                stack.addLast(c + "");
            } else if (c == ')') {
                // 找到匹配的括号
                while (!stack.getLast().equals("(")) {
                    suffix.add(stack.removeLast());
                }
                stack.removeLast();
            } else if (c == '*' || c == '/') {
                while ((!stack.isEmpty()) && (stack.getLast().equals("*") || stack.getLast().equals("/"))) {
                    suffix.add(stack.removeLast());
                }
                stack.addLast(c + "");
            } else if (c == '+' || c == '-') {
                while (topIsOperator(stack)) {
                    suffix.add(stack.removeLast());
                }
                stack.addLast(c + "");
            } else if (Character.isDigit(c)) {
                //查找完整数字
                StringBuilder stringBuilder = new StringBuilder();
                while (point < infixExpression.length() && Character.isDigit(infixExpression.charAt(point))) {
                    stringBuilder.append(infixExpression.charAt(point));
                    point++;
                }
                point--;
                suffix.add(stringBuilder.toString());
            } else if (Character.isLetter(c)) {
                StringBuilder stringBuilder = new StringBuilder();
                while (point < infixExpression.length() && Character.isLetter(infixExpression.charAt(point))) {
                    stringBuilder.append(infixExpression.charAt(point));
                    point++;
                }
                point--;
                if (variables.containsKey(stringBuilder.toString())) {
                    suffix.add(stringBuilder.toString());
                } else {
                    throw new RuntimeException("变量未定义");
                }
            } else {
                throw new RuntimeException("表达式错误");
            }
            point++;
        }
        while (!stack.isEmpty()) {
            suffix.add(stack.removeLast());
        }
        return suffix;

    }

    public Expression parse() {
        List<String> suffix = this.toSuffix();
        LinkedList<Expression> stack = new LinkedList<>();
        for (String item : suffix) {
            if (item.equals("+")) {
                Expression right = stack.removeLast();
                AddExpression addExpression = new AddExpression(stack.removeLast(), right);
                stack.addLast(addExpression);
            } else if (item.equals("-")) {
                Expression right = stack.removeLast();
                SubstractExpression substractExpression = new SubstractExpression(stack.removeLast(), right);
                stack.addLast(substractExpression);
            } else if (item.equals("*")) {
                Expression right = stack.removeLast();
                MultiplyExpression multiplyExpression = new MultiplyExpression(stack.removeLast(), right);
                stack.addLast(multiplyExpression);
            } else if (item.equals("/")) {
                Expression right = stack.removeLast();
                DevisionExpression devisionExpression = new DevisionExpression(stack.removeLast(), right);
                stack.addLast(devisionExpression);
            } else if (variables.containsKey(item)) {
                stack.addLast(new VirtualExpression(item, variables));
            } else {
                int value = Integer.parseInt(item);
                stack.addLast(new NuberExpression(value));
            }
        }
        return stack.getLast();

    }


    private boolean topIsOperator(LinkedList<String> stack) {
        if (stack.isEmpty()) {
            return false;
        }
        HashSet<Object> set = new HashSet<>();
        set.add("+");
        set.add("-");
        set.add("*");
        set.add("/");
        return set.contains(stack.getLast());
    }
}
